﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using CSScriptLibrary;
using LEDControllerTools.Controller;
using LEDControllerTools.IO;

namespace LEDControllerTools.Scripting
{
    public class ScriptEngine : IUpdateableStatus
    {
        public event StatusUpdateEventHandler StatusUpdate;

        readonly MethodDelegate _runner;
        readonly BackgroundWorker _bgWorker;

        public bool IsBusy { get { return _bgWorker.IsBusy; } }

        public ScriptEngine(string scriptPath)
        {

            OnStatusUpdate(string.Format(@"Reading Script: {0}", scriptPath));
            var code = FileReader.Read(scriptPath);

            string singleQuote = @"""";
            string doubleQuote = @"""""";

            _runner = CSScript.LoadMethod(
                @"
                using LEDControllerTools;
                public static void Run(LEDControllerTools.Controller.IControllable cont)
                {" + code + "}", new[] { @".\PIC.dll" }).GetStaticMethod();

            _bgWorker = new BackgroundWorker();
            _bgWorker.DoWork += bgWorker_DoWork;
            _bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;

        }

        public void Run(IControllable cont)
        {
            Run(cont, false);
        }

        public void Run(IControllable cont, bool repeat)
        {
            // Set up background worker object & hook up handlers
            _bgWorker.RunWorkerAsync(cont);
        }

        public static void WaitUntilNotBusy(ScriptEngine engine)
        {
            do { } while (engine.IsBusy);
        }

        private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            OnStatusUpdate("Script Complete!");
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            OnStatusUpdate("Executing Script...");
            try
            {
                _runner(e.Argument);
            }
            catch {}

        }

        private void OnStatusUpdate(string message)
        {
            if (StatusUpdate != null)
                StatusUpdate(this, message);
        }

    }
}
